import * as step from '@flow-step/step-toolkit'
import * as sinon from 'sinon';
import proxyquire from 'proxyquire';
import fs from 'fs';
import process from "process";
import { IParams } from '../src/params';
import { ArtifactDocker } from '@flow-step/step-toolkit/lib/artifact/artifact';

function createDirectorySync(path: string): void {
    try {
        fs.mkdirSync(path, {recursive: true});
        console.log(`Directory created at: ${path}`);
    } catch (err) {
        console.error(`Failed to create directory at: ${path}`, err);
    }
}

describe('buildPushImage', () => {
    let sandbox: sinon.SinonSandbox;
    let stepInfoStub: sinon.SinonStub;
    let buildPushImage: Function;
    let stepMock: {
        exec: {
            call: sinon.SinonStub,
        },
        artifact: {
            ArtifactDocker: Function;
            exportArtifactDocker: sinon.SinonStub;
        };
    };
    let processEnv: NodeJS.ProcessEnv;

    beforeEach(() => {
        processEnv = process.env;
        sandbox = sinon.createSandbox();
        stepInfoStub = sandbox.stub(step, 'info');

        // Mock dependencies
        stepMock = {
            exec: {
                call: sandbox.stub().resolves(0),
            },
            artifact: {
                ArtifactDocker: step.artifact.ArtifactDocker,
                exportArtifactDocker: sandbox.stub()
            }
        };

        const dockerToolkitMock = {
            formatContextPath: sandbox.stub().returns('/tmp/projectdir'),
        };

        const fsMock = {
            existsSync: sandbox.stub().returns(true),
            copyFileSync: sandbox.stub(),
            readFileSync: sandbox.stub().returns('FROM node\n')
        };

        const pathMock = {
            join: sandbox.stub().callsFake((...paths) => paths.join('/'))
        };

        // Proxyquire the module with mocked dependencies
        buildPushImage = proxyquire('../src/build-push', {
            '@flow-step/step-toolkit': stepMock,
            '@flow-step/dockertoolkit': dockerToolkitMock,
            'fs': fsMock,
            'path': pathMock
        }).buildPushImage;
    });

    afterEach(() => {
        process.env = processEnv;
        sandbox.restore();
    });

    it('should build and push an image without errors', async () => {
        delete process.env.NODEGROUP_TYPE
        createDirectorySync('/tmp/projectdir');

        const params = new IParams()

        params.projectDir = '/tmp/projectdir';
        params.dockerfilePath = '/tmp/projectdir/fake-dockerfile-path';
        params.contextPath = '';
        params.region = 'cn-beijing';
        params.dockerRepository = 'registry.cn-beijing.aliyuncs.com/rdc-builds-registry/base';
        params.useVpcAddress = true;
        params.dockerTag = "thedockertag";
        params.cacheType = 'no-cache';
        params.cacheImageId = '';
        params.options = '--platform linux/amd64';
        params.stepID = 'fake_step_id';
        params.artifact = 'my_image';

        await buildPushImage(params);
        sinon.assert.calledWith(stepMock.artifact.exportArtifactDocker, 'fake_step_id.DOCKER_TAG', sinon.match((artifact: ArtifactDocker) => {
            return artifact.DOCKER_URL === "registry.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag" &&
                   artifact.artifact === "DOCKER_TAG" && artifact.type === "docker_image" && artifact.dockerTag === "thedockertag"
        }));
        sinon.assert.calledWithMatch(stepMock.artifact.exportArtifactDocker, 'fake_step_id.DOCKER_OUTPUT', sinon.match((artifact: ArtifactDocker) => {
            return artifact.DOCKER_URL === "registry.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag" &&
                   artifact.artifact === "DOCKER_OUTPUT" && artifact.type === "docker_image" && artifact.dockerTag === "thedockertag"
        }))
        sinon.assert.calledWithMatch(stepMock.artifact.exportArtifactDocker, 'fake_step_id.DOCKER_OUTPUT_VPC', sinon.match((artifact: ArtifactDocker) => {
            return artifact.DOCKER_URL === "registry-vpc.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag" &&
                   artifact.artifact === "DOCKER_OUTPUT_VPC" && artifact.type === "docker_image" && artifact.dockerTag === "thedockertag"
        }))
        sinon.assert.calledWithMatch(stepMock.artifact.exportArtifactDocker, 'fake_step_id.artifact', sinon.match((artifact: ArtifactDocker) => {
            return artifact.DOCKER_URL === "registry.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag" &&
                   artifact.artifact === "my_image" && artifact.type === "docker_image" && artifact.dockerTag === "thedockertag"
        }))
        sinon.assert.calledWithMatch(stepMock.artifact.exportArtifactDocker, 'fake_step_id.artifact_vpc', sinon.match((artifact: ArtifactDocker) => {
                return artifact.DOCKER_URL === "registry-vpc.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag" &&
                       artifact.artifact === "my_image_vpc" && artifact.type === "docker_image" && artifact.dockerTag === "thedockertag"
            })
        )
        sinon.assert.calledWithMatch(stepMock.exec.call, "docker", [
            'buildx',
            'build',
            '--progress=plain',
            '-t',
            'registry-vpc.cn-beijing.aliyuncs.com/rdc-builds-registry/base:thedockertag',
            '-f',
            '/tmp/projectdir/fake-dockerfile-path',
            '/tmp/projectdir',
            '--push',
            '--no-cache',
            '--platform',
            'linux/amd64'
          ])
    });
});
